(*****************************************************************************
 * Delphi Plug-in Framework (DPF)
 * Copyright (C) 2006-2007 Tao Yuan
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the
 * License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.                                                               }
 *
 * The Initial Developer of the Original Code is Tao Yuan. Portions created by
 * Tao Yuan are Copyright (C) Tao Yuan (taoy.cn att gmail dott com)
 * All rights reserved.
 *****************************************************************************)
 
unit RDDefaultApplicationInitializer;

interface

uses
  Classes, SysUtils,
  Rcl,
  RDApplicationInitializer, RDPluginsCollector, RDApplication,
  RDBootErrorHandler, RDPluginManager, RDApplicationPlugin, RDPluginService,
  RDApplicationHelp;

const
  PARAM_APPLICATION_PLUGIN =
      'dpf.plugin.boot.applicationPlugin'; //$NON-NLS-1$
  PARAM_INTEGRITY_CHECK_MODE =
      'dpf.plugin.boot.integrityCheckMode'; //$NON-NLS-1$
  PARAM_PLUGINS_COLLECTOR =
      'dpf.plugin.boot.pluginsCollector'; //$NON-NLS-1$

type
  TDefaultApplicationInitializer = class(TInterfacedObject,
      IApplicationInitializer)
  private
    log: ILog;
    config: TExtendedProperties;
    integrityCheckMode: string;
    collector: IPluginsCollector;
    class function getCollectorInstance(className: string): IPluginsCollector;
  protected
    procedure configure(configuration: TExtendedProperties);
    function initApplication(errorHandler: IBootErrorHandler): TApplicationIntfs;
        overload;
    function initApplication(plugin: IPluginInfo; appPluginConfig:
        TExtendedProperties): IApplication; overload;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses
  DPFLog,
  RDBoot,
  RDDefaultPluginsCollector, RDResourceManager, RDObjectFactory, RDStandardPluginService;

constructor TDefaultApplicationInitializer.Create;
begin
end;

destructor TDefaultApplicationInitializer.Destroy;
begin
  inherited;
  // TODO -cMM: TDefaultApplicationInitializer.Destroy default body inserted
end;

{ TDefaultApplicationInitializer }

procedure TDefaultApplicationInitializer.configure(configuration:
    TExtendedProperties);
begin 
  // Initializing logging system.
  DPFLog.LogFactory.loadConfiguration('log4delphi.properties');
//  String log4jConfigKey = 'log4j.configuration'; //$NON-NLS-1$
//  if (System.getProperty(log4jConfigKey) == null) {
//      // Trying to find log4j configuration.
//      if (configuration.containsKey(log4jConfigKey)) {
//          System.setProperty(log4jConfigKey,
//                  configuration.getProperty(log4jConfigKey));
//      } else {
//          File log4jConfig = new File(
//                  configuration.getProperty('applicationRoot') //$NON-NLS-1$
//                  + File.separator + 'log4j.properties'); //$NON-NLS-1$
//          if (!log4jConfig.isFile()) {
//              log4jConfig = new File(
//                      configuration.getProperty('applicationRoot') //$NON-NLS-1$
//                      + File.separator + 'log4j.xml'); //$NON-NLS-1$
//          }
//          if (log4jConfig.isFile()) {
//              try {
//                  System.setProperty(log4jConfigKey,
//                          IoUtil.file2url(log4jConfig).toExternalForm());
//              } catch (MalformedURLException e) {
//                  // ignore
//              }
//          }
//      }
//  }
  log := DPFLog.LogFactory.getLogger(Self);
  log.info('logging system initialized'); //$NON-NLS-1$
  log.info('application root is ' //$NON-NLS-1$
          + configuration.getProperty('applicationRoot')); //$NON-NLS-1$
  config := configuration;
  integrityCheckMode :=
      configuration.getProperty(PARAM_INTEGRITY_CHECK_MODE, 'full'); //$NON-NLS-1$
  collector := getCollectorInstance(
          configuration.getProperty(PARAM_PLUGINS_COLLECTOR));
  collector.configure(configuration);
end;

class function TDefaultApplicationInitializer.getCollectorInstance(className:
    string): IPluginsCollector;
begin
  if (className <> '') then
  try
    GetClass(className).Create.GetInterface(IPluginsCollector, Result);
    Exit;
  except

  end;

  Result := IPluginsCollector(TDefaultPluginsCollector.Create);
end;

function TDefaultApplicationInitializer.initApplication(errorHandler:
    IBootErrorHandler): TApplicationIntfs;
var
  objFactory: TObjectFactory;
  pluginLocations: ICollection;  
  appPluginId: string;
begin
  // Prepare parameters to start plug-in manager.
  log.debug('collecting plug-in locations');
  pluginLocations := collector.collectPluginLocations();
  log.debug('collected ' + IntToStr(pluginLocations.size)
          + ' plug-in locations, running plug-in manager');
  // Create instance of plug-in manager providing collection
  // of discovered plug-in manifests and corresponding plug-in folders.
  objFactory := TObjectFactory.newFactory(config);
  pluginManager := objFactory.createManager();
  objFactory.Free;

  PluginService := TPluginService.Create(pluginManager);

  pluginManager.publishPlugins(IList(pluginLocations));

  if not Rcl.Str.IsEqual('off', integrityCheckMode) then
  begin
    // Check plug-in's integrity.
    log.debug('checking plug-ins set integrity');
//    IntegrityCheckReport integrityCheckReport =
//        pluginManager.getRegistry().checkIntegrity(
//                'light'.equalsIgnoreCase(integrityCheckMode) ? null
//                    : pluginManager.getPathResolver());
//    log.info('integrity check done: errors - '
//            + integrityCheckReport.countErrors() + ', warnings - '
//            + integrityCheckReport.countWarnings());
//    if (integrityCheckReport.countErrors() != 0) {
//        // Something wrong in plug-ins set.
//        log.info(integrityCheckReport2str(integrityCheckReport));
//        if (!errorHandler.handleError(ResourceManager.getMessage(
//                Boot.PACKAGE_NAME, 'integrityCheckFailed'),
//                integrityCheckReport)) {
//            return null;
//        } else if (log.isDebugEnabled()
//              && ((integrityCheckReport.countErrors() > 0)
//              || (integrityCheckReport.countWarnings() > 0))) {
//          log.debug(integrityCheckReport2str(integrityCheckReport));
//      }
  end;

  // application plug-in ID
  appPluginId := config.getProperty(PARAM_APPLICATION_PLUGIN);
  log.info('application plug-in is ' + appPluginId); 
  // get the start-up application plug-in
  Result.PluginInfo := pluginManager.getPlugin(appPluginId);
  log.debug('got application plug-in ' + (Result.PluginInfo as IPlugin).getName
          + ', initializing application');
  Result.App := initApplication(Result.PluginInfo,
          config.getSubset(appPluginId + '.'));
end;

function TDefaultApplicationInitializer.initApplication(plugin: IPluginInfo;
    appPluginConfig: TExtendedProperties): IApplication;
var
//  mtd: TInitAppInvokeMethod;
  applicationPlugin: IApplicationPlugin;
begin
  if Supports(plugin.Plugin, IApplicationPlugin, applicationPlugin) then
  begin
    Result := applicationPlugin.initApplication(
            appPluginConfig);
    Exit;
  end;
  raise Exception.Create('application plug-in class '
          + (plugin as IPlugin).getName
          + ' doesn''t assignable with IApplicationPlugin');
//  log.debug('application plug-in class '
//          + plugin.getName
//          + ' doesn''t assignable with '
//          + TApplicationPlugin.ClassName
//          + ', will try to find '
//          + '[dpfApplication initApplication(Properties)] method');
//  @mtd := TObject(plugin).MethodAddress('initApplication'); 
//
//  if (@mtd = nil) then
//      raise Exception.Create(ResourceManager.getMessage(TBoot.PACKAGE_NAME,
//              'initMethodNotFound', [
//              'dpfApplication initApplication(Properties)', 
//              plugin.getName]));
//
//  try 
//      Result := mtd(appPluginConfig);
//  except
//  end;
end;

end.
